/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.v4.view.accessibility;

import android.graphics.Rect;
//import android.os.Build;
import android.view.View;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo}
 * introduced after API level 4 in a backwards compatible fashion.
 */
public class AccessibilityNodeInfoCompat {

	static interface AccessibilityNodeInfoImpl {
		public Object obtain();

		public Object obtain(View source);

		public Object obtain(Object info);

		public void setSource(Object info, View source);

		public int getWindowId(Object info);

		public int getChildCount(Object info);

		public Object getChild(Object info, int index);

		public void addChild(Object info, View child);

		public int getActions(Object info);

		public void addAction(Object info, int action);

		public boolean performAction(Object info, int action);

		public List<Object> findAccessibilityNodeInfosByText(Object info, String text);

		public Object getParent(Object info);

		public void setParent(Object info, View parent);

		public void getBoundsInParent(Object info, Rect outBounds);

		public void setBoundsInParent(Object info, Rect bounds);

		public void getBoundsInScreen(Object info, Rect outBounds);

		public void setBoundsInScreen(Object info, Rect bounds);

		public boolean isCheckable(Object info);

		public void setCheckable(Object info, boolean checkable);

		public boolean isChecked(Object info);

		public void setChecked(Object info, boolean checked);

		public boolean isFocusable(Object info);

		public void setFocusable(Object info, boolean focusable);

		public boolean isFocused(Object info);

		public void setFocused(Object info, boolean focused);

		public boolean isSelected(Object info);

		public void setSelected(Object info, boolean selected);

		public boolean isClickable(Object info);

		public void setClickable(Object info, boolean clickable);

		public boolean isLongClickable(Object info);

		public void setLongClickable(Object info, boolean longClickable);

		public boolean isEnabled(Object info);

		public void setEnabled(Object info, boolean enabled);

		public boolean isPassword(Object info);

		public void setPassword(Object info, boolean password);

		public boolean isScrollable(Object info);

		public void setScrollable(Object info, boolean scrollable);

		public CharSequence getPackageName(Object info);

		public void setPackageName(Object info, CharSequence packageName);

		public CharSequence getClassName(Object info);

		public void setClassName(Object info, CharSequence className);

		public CharSequence getText(Object info);

		public void setText(Object info, CharSequence text);

		public CharSequence getContentDescription(Object info);

		public void setContentDescription(Object info, CharSequence contentDescription);

		public void recycle(Object info);
	}

	static class AccessibilityNodeInfoStubImpl implements AccessibilityNodeInfoImpl {
		public Object obtain() {
			return null;
		}

		public Object obtain(View source) {
			return null;
		}

		public Object obtain(Object info) {
			return null;
		}

		public void addAction(Object info, int action) {

		}

		public void addChild(Object info, View child) {

		}

		public List<Object> findAccessibilityNodeInfosByText(Object info, String text) {
			return Collections.emptyList();
		}

		public int getActions(Object info) {
			return 0;
		}

		public void getBoundsInParent(Object info, Rect outBounds) {

		}

		public void getBoundsInScreen(Object info, Rect outBounds) {

		}

		public Object getChild(Object info, int index) {
			return null;
		}

		public int getChildCount(Object info) {
			return 0;
		}

		public CharSequence getClassName(Object info) {
			return null;
		}

		public CharSequence getContentDescription(Object info) {
			return null;
		}

		public CharSequence getPackageName(Object info) {
			return null;
		}

		public AccessibilityNodeInfoCompat getParent(Object info) {
			return null;
		}

		public CharSequence getText(Object info) {
			return null;
		}

		public int getWindowId(Object info) {
			return 0;
		}

		public boolean isCheckable(Object info) {
			return false;
		}

		public boolean isChecked(Object info) {
			return false;
		}

		public boolean isClickable(Object info) {
			return false;
		}

		public boolean isEnabled(Object info) {
			return false;
		}

		public boolean isFocusable(Object info) {
			return false;
		}

		public boolean isFocused(Object info) {
			return false;
		}

		public boolean isLongClickable(Object info) {
			return false;
		}

		public boolean isPassword(Object info) {
			return false;
		}

		public boolean isScrollable(Object info) {
			return false;
		}

		public boolean isSelected(Object info) {
			return false;
		}

		public boolean performAction(Object info, int action) {
			return false;
		}

		public void setBoundsInParent(Object info, Rect bounds) {

		}

		public void setBoundsInScreen(Object info, Rect bounds) {

		}

		public void setCheckable(Object info, boolean checkable) {

		}

		public void setChecked(Object info, boolean checked) {

		}

		public void setClassName(Object info, CharSequence className) {

		}

		public void setClickable(Object info, boolean clickable) {

		}

		public void setContentDescription(Object info, CharSequence contentDescription) {

		}

		public void setEnabled(Object info, boolean enabled) {

		}

		public void setFocusable(Object info, boolean focusable) {

		}

		public void setFocused(Object info, boolean focused) {

		}

		public void setLongClickable(Object info, boolean longClickable) {

		}

		public void setPackageName(Object info, CharSequence packageName) {

		}

		public void setParent(Object info, View parent) {

		}

		public void setPassword(Object info, boolean password) {

		}

		public void setScrollable(Object info, boolean scrollable) {

		}

		public void setSelected(Object info, boolean selected) {

		}

		public void setSource(Object info, View source) {

		}

		public void setText(Object info, CharSequence text) {

		}

		public void recycle(Object info) {

		}
	}

	/*
	 * static class AccessibilityNodeInfoIcsImpl extends
	 * AccessibilityNodeInfoStubImpl {
	 * 
	 * @Override public Object obtain() { return
	 * AccessibilityNodeInfoCompatIcs.obtain(); }
	 * 
	 * @Override public Object obtain(View source) { return
	 * AccessibilityNodeInfoCompatIcs.obtain(source); }
	 * 
	 * @Override public Object obtain(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.obtain(info); }
	 * 
	 * @Override public void addAction(Object info, int action) {
	 * AccessibilityNodeInfoCompatIcs.addAction(info, action); }
	 * 
	 * @Override public void addChild(Object info, View child) {
	 * AccessibilityNodeInfoCompatIcs.addChild(info, child); }
	 * 
	 * @Override public List<Object> findAccessibilityNodeInfosByText(Object
	 * info, String text) { return
	 * AccessibilityNodeInfoCompatIcs.findAccessibilityNodeInfosByText(info,
	 * text); }
	 * 
	 * @Override public int getActions(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getActions(info); }
	 * 
	 * @Override public void getBoundsInParent(Object info, Rect outBounds) {
	 * AccessibilityNodeInfoCompatIcs.getBoundsInParent(info, outBounds); }
	 * 
	 * @Override public void getBoundsInScreen(Object info, Rect outBounds) {
	 * AccessibilityNodeInfoCompatIcs.getBoundsInScreen(info, outBounds); }
	 * 
	 * @Override public AccessibilityNodeInfoCompat getChild(Object info, int
	 * index) { return new AccessibilityNodeInfoCompat(IMPL.getChild(info,
	 * index)); }
	 * 
	 * @Override public int getChildCount(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getChildCount(info); }
	 * 
	 * @Override public CharSequence getClassName(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getClassName(info); }
	 * 
	 * @Override public CharSequence getContentDescription(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getContentDescription(info); }
	 * 
	 * @Override public CharSequence getPackageName(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getPackageName(info); }
	 * 
	 * @Override public AccessibilityNodeInfoCompat getParent(Object info) {
	 * return new AccessibilityNodeInfoCompat(IMPL.getParent(info)); }
	 * 
	 * @Override public CharSequence getText(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getText(info); }
	 * 
	 * @Override public int getWindowId(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.getWindowId(info); }
	 * 
	 * @Override public boolean isCheckable(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isCheckable(info); }
	 * 
	 * @Override public boolean isChecked(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isChecked(info); }
	 * 
	 * @Override public boolean isClickable(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isClickable(info); }
	 * 
	 * @Override public boolean isEnabled(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isEnabled(info); }
	 * 
	 * @Override public boolean isFocusable(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isFocusable(info); }
	 * 
	 * @Override public boolean isFocused(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isFocused(info); }
	 * 
	 * @Override public boolean isLongClickable(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isLongClickable(info); }
	 * 
	 * @Override public boolean isPassword(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isPassword(info); }
	 * 
	 * @Override public boolean isScrollable(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isScrollable(info); }
	 * 
	 * @Override public boolean isSelected(Object info) { return
	 * AccessibilityNodeInfoCompatIcs.isSelected(info); }
	 * 
	 * @Override public boolean performAction(Object info, int action) { return
	 * AccessibilityNodeInfoCompatIcs.performAction(info, action); }
	 * 
	 * @Override public void setBoundsInParent(Object info, Rect bounds) {
	 * AccessibilityNodeInfoCompatIcs.setBoundsInParent(info, bounds); }
	 * 
	 * @Override public void setBoundsInScreen(Object info, Rect bounds) {
	 * AccessibilityNodeInfoCompatIcs.setBoundsInScreen(info, bounds); }
	 * 
	 * @Override public void setCheckable(Object info, boolean checkable) {
	 * AccessibilityNodeInfoCompatIcs.setCheckable(info, checkable); }
	 * 
	 * @Override public void setChecked(Object info, boolean checked) {
	 * AccessibilityNodeInfoCompatIcs.setChecked(info, checked); }
	 * 
	 * @Override public void setClassName(Object info, CharSequence className) {
	 * AccessibilityNodeInfoCompatIcs.setClassName(info, className); }
	 * 
	 * @Override public void setClickable(Object info, boolean clickable) {
	 * AccessibilityNodeInfoCompatIcs.setClickable(info, clickable); }
	 * 
	 * @Override public void setContentDescription(Object info, CharSequence
	 * contentDescription) {
	 * AccessibilityNodeInfoCompatIcs.setContentDescription(info,
	 * contentDescription); }
	 * 
	 * @Override public void setEnabled(Object info, boolean enabled) {
	 * AccessibilityNodeInfoCompatIcs.setEnabled(info, enabled); }
	 * 
	 * @Override public void setFocusable(Object info, boolean focusable) {
	 * AccessibilityNodeInfoCompatIcs.setFocusable(info, focusable); }
	 * 
	 * @Override public void setFocused(Object info, boolean focused) {
	 * AccessibilityNodeInfoCompatIcs.setFocused(info, focused); }
	 * 
	 * @Override public void setLongClickable(Object info, boolean
	 * longClickable) { AccessibilityNodeInfoCompatIcs.setLongClickable(info,
	 * longClickable); }
	 * 
	 * @Override public void setPackageName(Object info, CharSequence
	 * packageName) { AccessibilityNodeInfoCompatIcs.setPackageName(info,
	 * packageName); }
	 * 
	 * @Override public void setParent(Object info, View parent) {
	 * AccessibilityNodeInfoCompatIcs.setParent(info, parent); }
	 * 
	 * @Override public void setPassword(Object info, boolean password) {
	 * AccessibilityNodeInfoCompatIcs.setPassword(info, password); }
	 * 
	 * @Override public void setScrollable(Object info, boolean scrollable) {
	 * AccessibilityNodeInfoCompatIcs.setScrollable(info, scrollable); }
	 * 
	 * @Override public void setSelected(Object info, boolean selected) {
	 * AccessibilityNodeInfoCompatIcs.setSelected(info, selected); }
	 * 
	 * @Override public void setSource(Object info, View source) {
	 * AccessibilityNodeInfoCompatIcs.setSource(info, source); }
	 * 
	 * @Override public void setText(Object info, CharSequence text) {
	 * AccessibilityNodeInfoCompatIcs.setText(info, text); }
	 * 
	 * @Override public void recycle(Object info) {
	 * AccessibilityNodeInfoCompatIcs.recycle(info); } }
	 */
	static {
		// if (Build.VERSION.SDK_INT >= 14) { // ICS
		// IMPL = new AccessibilityNodeInfoIcsImpl();
		// } else {
		IMPL = new AccessibilityNodeInfoStubImpl();
		// }
	}

	private static final AccessibilityNodeInfoImpl IMPL;

	private final Object mInfo;

	// Actions.

	/**
	 * Action that focuses the node.
	 */
	public static final int ACTION_FOCUS = 0x00000001;

	/**
	 * Action that unfocuses the node.
	 */
	public static final int ACTION_CLEAR_FOCUS = 0x00000002;

	/**
	 * Action that selects the node.
	 */
	public static final int ACTION_SELECT = 0x00000004;

	/**
	 * Action that unselects the node.
	 */
	public static final int ACTION_CLEAR_SELECTION = 0x00000008;

	/*
	 * Hide constructor from clients.
	 */
	public AccessibilityNodeInfoCompat(Object info) {
		mInfo = info;
	}

	/**
	 * @return The wrapped actual implementation.
	 * 
	 * @hide
	 */
	public Object getImpl() {
		return mInfo;
	}

	/**
	 * Returns a cached instance if such is available otherwise a new one and
	 * sets the source.
	 * 
	 * @return An instance.
	 * @see #setSource(View)
	 */
	public static AccessibilityNodeInfoCompat obtain(View source) {
		return new AccessibilityNodeInfoCompat(IMPL.obtain(source));
	}

	/**
	 * Returns a cached instance if such is available otherwise a new one.
	 * 
	 * @return An instance.
	 */
	public static AccessibilityNodeInfoCompat obtain() {
		return new AccessibilityNodeInfoCompat(IMPL.obtain());
	}

	/**
	 * Returns a cached instance if such is available or a new one is create.
	 * The returned instance is initialized from the given <code>info</code>.
	 * 
	 * @param info
	 *            The other info.
	 * @return An instance.
	 */
	public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) {
		return new AccessibilityNodeInfoCompat(IMPL.obtain(info.mInfo));
	}

	/**
	 * Sets the source.
	 * 
	 * @param source
	 *            The info source.
	 */
	public void setSource(View source) {
		IMPL.setSource(mInfo, source);
	}

	/**
	 * Gets the id of the window from which the info comes from.
	 * 
	 * @return The window id.
	 */
	public int getWindowId() {
		return IMPL.getWindowId(mInfo);
	}

	/**
	 * Gets the number of children.
	 * 
	 * @return The child count.
	 */
	public int getChildCount() {
		return IMPL.getChildCount(mInfo);
	}

	/**
	 * Get the child at given index.
	 * <p>
	 * <strong>Note:</strong> It is a client responsibility to recycle the
	 * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} to
	 * avoid creating of multiple instances.
	 * </p>
	 * 
	 * @param index
	 *            The child index.
	 * @return The child node.
	 * @throws IllegalStateException
	 *             If called outside of an AccessibilityService.
	 */
	public AccessibilityNodeInfoCompat getChild(int index) {
		return new AccessibilityNodeInfoCompat(IMPL.getChild(mInfo, index));
	}

	/**
	 * Adds a child.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param child
	 *            The child.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void addChild(View child) {
		IMPL.addChild(mInfo, child);
	}

	/**
	 * Gets the actions that can be performed on the node.
	 * 
	 * @return The bit mask of with actions.
	 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS
	 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
	 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT
	 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
	 */
	public int getActions() {
		return IMPL.getActions(mInfo);
	}

	/**
	 * Adds an action that can be performed on the node.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param action
	 *            The action.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void addAction(int action) {
		IMPL.addAction(mInfo, action);
	}

	/**
	 * Performs an action on the node.
	 * <p>
	 * <strong>Note:</strong> An action can be performed only if the request is
	 * made from an {@link android.accessibilityservice.AccessibilityService}.
	 * </p>
	 * 
	 * @param action
	 *            The action to perform.
	 * @return True if the action was performed.
	 * @throws IllegalStateException
	 *             If called outside of an AccessibilityService.
	 */
	public boolean performAction(int action) {
		return IMPL.performAction(mInfo, action);
	}

	/**
	 * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text.
	 * The match is case insensitive containment. The search is relative to this
	 * info i.e. this info is the root of the traversed tree.
	 * <p>
	 * <strong>Note:</strong> It is a client responsibility to recycle the
	 * received info by calling
	 * {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} to
	 * avoid creating of multiple instances.
	 * </p>
	 * 
	 * @param text
	 *            The searched text.
	 * @return A list of node info.
	 */
	public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) {
		List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
		List<Object> infos = IMPL.findAccessibilityNodeInfosByText(mInfo, text);
		final int infoCount = infos.size();
		for (int i = 0; i < infoCount; i++) {
			Object info = infos.get(i);
			result.add(new AccessibilityNodeInfoCompat(info));
		}
		return result;
	}

	/**
	 * Gets the parent.
	 * <p>
	 * <strong>Note:</strong> It is a client responsibility to recycle the
	 * received info by calling
	 * {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} to
	 * avoid creating of multiple instances.
	 * </p>
	 * 
	 * @return The parent.
	 */
	public AccessibilityNodeInfoCompat getParent() {
		return new AccessibilityNodeInfoCompat(IMPL.getParent(mInfo));
	}

	/**
	 * Sets the parent.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param parent
	 *            The parent.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setParent(View parent) {
		IMPL.setParent(mInfo, parent);
	}

	/**
	 * Gets the node bounds in parent coordinates.
	 * 
	 * @param outBounds
	 *            The output node bounds.
	 */
	public void getBoundsInParent(Rect outBounds) {
		IMPL.getBoundsInParent(mInfo, outBounds);
	}

	/**
	 * Sets the node bounds in parent coordinates.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param bounds
	 *            The node bounds.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setBoundsInParent(Rect bounds) {
		IMPL.setBoundsInParent(mInfo, bounds);
	}

	/**
	 * Gets the node bounds in screen coordinates.
	 * 
	 * @param outBounds
	 *            The output node bounds.
	 */
	public void getBoundsInScreen(Rect outBounds) {
		IMPL.getBoundsInScreen(mInfo, outBounds);
	}

	/**
	 * Sets the node bounds in screen coordinates.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param bounds
	 *            The node bounds.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setBoundsInScreen(Rect bounds) {
		IMPL.setBoundsInParent(mInfo, bounds);
	}

	/**
	 * Gets whether this node is checkable.
	 * 
	 * @return True if the node is checkable.
	 */
	public boolean isCheckable() {
		return IMPL.isCheckable(mInfo);
	}

	/**
	 * Sets whether this node is checkable.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param checkable
	 *            True if the node is checkable.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setCheckable(boolean checkable) {
		IMPL.setCheckable(mInfo, checkable);
	}

	/**
	 * Gets whether this node is checked.
	 * 
	 * @return True if the node is checked.
	 */
	public boolean isChecked() {
		return IMPL.isChecked(mInfo);
	}

	/**
	 * Sets whether this node is checked.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param checked
	 *            True if the node is checked.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setChecked(boolean checked) {
		IMPL.setChecked(mInfo, checked);
	}

	/**
	 * Gets whether this node is focusable.
	 * 
	 * @return True if the node is focusable.
	 */
	public boolean isFocusable() {
		return IMPL.isFocusable(mInfo);
	}

	/**
	 * Sets whether this node is focusable.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param focusable
	 *            True if the node is focusable.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setFocusable(boolean focusable) {
		IMPL.setFocusable(mInfo, focusable);
	}

	/**
	 * Gets whether this node is focused.
	 * 
	 * @return True if the node is focused.
	 */
	public boolean isFocused() {
		return IMPL.isFocused(mInfo);
	}

	/**
	 * Sets whether this node is focused.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param focused
	 *            True if the node is focused.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setFocused(boolean focused) {
		IMPL.setFocused(mInfo, focused);
	}

	/**
	 * Gets whether this node is selected.
	 * 
	 * @return True if the node is selected.
	 */
	public boolean isSelected() {
		return IMPL.isSelected(mInfo);
	}

	/**
	 * Sets whether this node is selected.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param selected
	 *            True if the node is selected.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setSelected(boolean selected) {
		IMPL.setSelected(mInfo, selected);
	}

	/**
	 * Gets whether this node is clickable.
	 * 
	 * @return True if the node is clickable.
	 */
	public boolean isClickable() {
		return IMPL.isClickable(mInfo);
	}

	/**
	 * Sets whether this node is clickable.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param clickable
	 *            True if the node is clickable.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setClickable(boolean clickable) {
		IMPL.setClickable(mInfo, clickable);
	}

	/**
	 * Gets whether this node is long clickable.
	 * 
	 * @return True if the node is long clickable.
	 */
	public boolean isLongClickable() {
		return IMPL.isLongClickable(mInfo);
	}

	/**
	 * Sets whether this node is long clickable.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param longClickable
	 *            True if the node is long clickable.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setLongClickable(boolean longClickable) {
		IMPL.setLongClickable(mInfo, longClickable);
	}

	/**
	 * Gets whether this node is enabled.
	 * 
	 * @return True if the node is enabled.
	 */
	public boolean isEnabled() {
		return IMPL.isEnabled(mInfo);
	}

	/**
	 * Sets whether this node is enabled.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param enabled
	 *            True if the node is enabled.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setEnabled(boolean enabled) {
		IMPL.setEnabled(mInfo, enabled);
	}

	/**
	 * Gets whether this node is a password.
	 * 
	 * @return True if the node is a password.
	 */
	public boolean isPassword() {
		return IMPL.isPassword(mInfo);
	}

	/**
	 * Sets whether this node is a password.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param password
	 *            True if the node is a password.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setPassword(boolean password) {
		IMPL.setPassword(mInfo, password);
	}

	/**
	 * Gets if the node is scrollable.
	 * 
	 * @return True if the node is scrollable, false otherwise.
	 */
	public boolean isScrollable() {
		return IMPL.isScrollable(mInfo);
	}

	/**
	 * Sets if the node is scrollable.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param scrollable
	 *            True if the node is scrollable, false otherwise.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setScrollable(boolean scrollable) {
		IMPL.setScrollable(mInfo, scrollable);
	}

	/**
	 * Gets the package this node comes from.
	 * 
	 * @return The package name.
	 */
	public CharSequence getPackageName() {
		return IMPL.getPackageName(mInfo);
	}

	/**
	 * Sets the package this node comes from.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param packageName
	 *            The package name.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setPackageName(CharSequence packageName) {
		IMPL.setPackageName(mInfo, packageName);
	}

	/**
	 * Gets the class this node comes from.
	 * 
	 * @return The class name.
	 */
	public CharSequence getClassName() {
		return IMPL.getClassName(mInfo);
	}

	/**
	 * Sets the class this node comes from.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param className
	 *            The class name.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setClassName(CharSequence className) {
		IMPL.setClassName(mInfo, className);
	}

	/**
	 * Gets the text of this node.
	 * 
	 * @return The text.
	 */
	public CharSequence getText() {
		return IMPL.getText(mInfo);
	}

	/**
	 * Sets the text of this node.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param text
	 *            The text.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setText(CharSequence text) {
		IMPL.setText(mInfo, text);
	}

	/**
	 * Gets the content description of this node.
	 * 
	 * @return The content description.
	 */
	public CharSequence getContentDescription() {
		return IMPL.getContentDescription(mInfo);
	}

	/**
	 * Sets the content description of this node.
	 * <p>
	 * <strong>Note:</strong> Cannot be called from an
	 * {@link android.accessibilityservice.AccessibilityService}. This class is
	 * made immutable before being delivered to an AccessibilityService.
	 * </p>
	 * 
	 * @param contentDescription
	 *            The content description.
	 * @throws IllegalStateException
	 *             If called from an AccessibilityService.
	 */
	public void setContentDescription(CharSequence contentDescription) {
		IMPL.setContentDescription(mInfo, contentDescription);
	}

	/**
	 * Return an instance back to be reused.
	 * <p>
	 * <strong>Note:</strong> You must not touch the object after calling this
	 * function.
	 * 
	 * @throws IllegalStateException
	 *             If the info is already recycled.
	 */
	public void recycle() {
		IMPL.recycle(mInfo);
	}

	@Override
	public int hashCode() {
		return (mInfo == null) ? 0 : mInfo.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj;
		if (mInfo == null) {
			if (other.mInfo != null) {
				return false;
			}
		} else if (!mInfo.equals(other.mInfo)) {
			return false;
		}
		return true;
	}
}
